from typing_extensions import Self
import serial.tools.list_ports
import sys
from src.utils.loguru_func import serial_port_logger
import serial
import time


def get_available_ports():
    """
    扫描并返回当前电脑所有可用的串口信息。

    :return: 包含可用串口信息的列表，每个元素是一个包含设备名、描述和硬件 ID 的元组
    """
    ports = serial.tools.list_ports.comports()
    available_ports = {}
    for port in ports:
        available_ports[port.device] = (
            port.device, port.description, port.hwid)
    return available_ports


def show_available_ports():
    ports = get_available_ports()
    if ports:
        serial_port_logger.debug(
            f'检测到以下串口：：')

        for port in ports.values():
            serial_port_logger.debug(
                f'设备名: {port[0]}, 描述: {port[1]}, 硬件 ID: {port[2]}')

    else:
        serial_port_logger.debug(
            f'未检测到可用串口')


class SerialCommunication:
    _Obj_dict = {}

    def __new__(cls, port) -> Self:
        if port not in SerialCommunication._Obj_dict:
            SerialCommunication._Obj_dict[port] = super().__new__(cls)
        return SerialCommunication._Obj_dict[port]

    def __init__(self, port, baudrate=9600, timeout=1):
        """
        初始化串口通信对象
        :param port: 串口号，例如 'COM3' 或 '/dev/ttyUSB0'
        :param baudrate: 波特率，默认为 9600
        :param timeout: 超时时间，单位为秒，默认为 1 秒
        """

        # 如果已经初始化了，就会有ser属性，直接返回
        if hasattr(self, 'ser'):
            return
        self.ser = serial.Serial(
            port=port,
            baudrate=baudrate,
            timeout=timeout
        )

    def is_open(self):
        """
        检查串口是否打开

        :return: 如果串口打开返回 True，否则返回 False
        """
        return self.ser.is_open

    def open_port(self):
        """
        打开串口
        """
        if not self.ser.is_open:
            self.ser.open()
            serial_port_logger.debug(f'open_port:{self.ser.port}')

    def close_port(self):
        """
        关闭串口
        """
        if self.ser.is_open:
            self.ser.close()
            serial_port_logger.debug(f'close_port:{self.ser.port}')

    def send_data(self, data):
        """
        向串口发送数据
        :param data: 要发送的数据，可以是字符串或字节类型
        :return: 发送的字节数
        """
        if isinstance(data, str):
            # data = dota.encode('utf-8')
            data = bytes.fromhex(data.replace(' ', ''))
        serial_port_logger.debug(f'send_data:{data}')
        return self.ser.write(data)

    def receive_data(self, num_bytes=1024):
        """
        从串口接收数据
        :param num_bytes: 要接收的最大字节数，默认为 1024 字节
        :return: 接收到的数据，字节类型
        """

        data = self.ser.read(num_bytes)
        serial_port_logger.debug(f'receive_data:{data}')
        return data

    def receive_data_until(self, expected=b'\n'):
        """
        从串口接收数据直到遇到指定的分隔符

        :param expected: 分隔符，字节类型，默认为换行符 b'\n'
        :return: 接收到的数据，字节类型
        """
        return self.ser.read_until(expected)


class SerialEcho:
    def __init__(self, port, baudrate=9600, timeout=1):
        """
        初始化串口回显对象

        :param port: 串口号，例如 'COM3' 或 '/dev/ttyUSB0'
        :param baudrate: 波特率，默认为 9600
        :param timeout: 超时时间，单位为秒，默认为 1 秒
        """
        self.serial_comm = SerialCommunication(port, baudrate, timeout)

    def start_echo(self):
        """
        启动串口回显功能，持续接收数据并原样发回
        """
        try:
            if not self.serial_comm.is_open():
                self.serial_comm.open_port()
            serial_port_logger.debug("串口回显功能已启动")
            while True:
                # 接收数据
                received_data = self.serial_comm.receive_data()
                if received_data:
                    # 原样发回数据
                    self.serial_comm.send_data(received_data)
                    serial_port_logger.debug(f"接收到数据: {received_data}, 已原样发回")
        except KeyboardInterrupt:
            serial_port_logger.debug("用户手动终止回显功能")
        except serial.SerialException as e:
            serial_port_logger.debug(f"串口通信出错: {e}")
        finally:
            if self.serial_comm.is_open():
                self.serial_comm.close_port()
                serial_port_logger.debug("串口已关闭")

# if __name__ == "__main__":


def test_serial_communication():
    # 使用示例
    try:
        # 请根据实际情况修改串口号
        serial_comm = SerialCommunication(port='COM3')
        if serial_comm.is_open():
            serial_port_logger.debug("串口已打开")
            # 发送数据
            send_data = "Hello, Serial!"
            bytes_sent = serial_comm.send_data(send_data)
            serial_port_logger.debug(f"已发送 {bytes_sent} 字节数据: {send_data}")

            # 等待一段时间，确保设备有时间响应
            time.sleep(1)

            # 接收数据
            received_data = serial_comm.receive_data()
            serial_port_logger.debug(
                f"接收到的数据: {received_data.decode('utf-8')}")

    except serial.SerialException as e:
        serial_port_logger.debug(f"串口通信出错: {e}")
    finally:
        if 'serial_comm' in locals() and serial_comm.is_open():
            serial_comm.close_port()
            serial_port_logger.debug("串口已关闭")
